/*
 * This file is part of Cadmium.
 * Copyright (C) 2007-2010 Xavier Clerc.
 *
 * Cadmium is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Cadmium is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fr.x9c.cadmium.kernel;

import java.io.InputStream;
import java.io.PrintStream;
import java.util.Arrays;

/**
 * This abstract class defines the basic elements common to all parameters.
 *
 * @author <a href="mailto:cadmium@x9c.fr">Xavier Clerc</a>
 * @version 1.1
 * @since 1.0
 */
public abstract class AbstractParameters {

    /** Arguments to program. */
    protected final String[] arguments;

    /** Whether backtrace is requested. */
    protected final boolean backtrace;

    /** Whether <i>exit</i> primitive should stop JVM. */
    protected final boolean exitStoppingJVM;

    /** Standard input of program. */
    protected final InputStream in;

    /** Standard output of program. */
    protected final PrintStream out;

    /** Standard error of program. */
    protected final PrintStream err;

    /** Whether <i>Graphics</i> frame should be AWT. */
    protected final boolean awt;

    /**
     * Whether <i>Graphics</i> component should be a bare canvas (no frame).
     * <br/>
     * For internal use.
     */
    protected final boolean bareCanvas;

    /**
     * Whether <tt>javax.sound</tt> should be used for <i>Graphics</i> beeps.
     */
    protected final boolean javaxSound;


    /** Whether <i>JDBM</i> should be used for <i>Dbm</i> implementation. */
    protected final boolean jdbm;

    /** Underlying OS identifier. */
    protected final String os;

    /** Whether unix primitives should be emulated. */
    protected final boolean unixEmulation;

    /** Program file. */
    protected final String file;

    /** Whether embedded mode is activated. */
    protected final boolean embedded;

    /** Base class for embedded mode. */
    protected final String embeddedBase;

    /**
     * Constructs parameters from explicit values.
     * @param arguments arguments to program
     *                  - should not be <tt>null</tt>
     * @param backtrace whether backtrace is requested
     * @param exitStoppingJVM whether <i>exit</i> primitive should stop JVM
     * @param in standard input of program
     *           - should not be <tt>null</tt>
     * @param out standard output of program
     *            - should not be <tt>null</tt>
     * @param err standard error of program
     *            - should not be <tt>null</tt>
     * @param awt whether <i>Graphics</i> frame should be AWT
     * @param bareCanvas whether <i>Graphics</i> component should be a bare
     *                   canvas (no frame)
     * @param javaxSound whether <tt>javax.sound</tt> should be used for
     *                   <i>Graphics</i> beeps
     * @param jdbm whether <i>JDBM</i> should be used as the <i>Dbm</i> implementation
     * @param os underlying OS identifier - should not be <tt>null</tt>
     * @param unixEmulation whether unix primitives should be emulated
     * @param file file to be interpreted/executed
     * @param embedded whether embedded mode is activated
     * @param embeddedBase base class for embedded mode
     */
    public AbstractParameters(final String[] arguments,
                              final boolean backtrace,
                              final boolean exitStoppingJVM,
                              final InputStream in,
                              final PrintStream out,
                              final PrintStream err,
                              final boolean awt,
                              final boolean bareCanvas,
                              final boolean javaxSound,
                              final boolean jdbm,
                              final String os,
                              final boolean unixEmulation,
                              final String file,
                              final boolean embedded,
                              final String embeddedBase) {
        assert arguments != null : "null arguments";
        assert in != null : "null in";
        assert out != null : "null out";
        assert err != null : "null err";
        assert os != null : "null os";
        this.arguments = Arrays.copyOf(arguments, arguments.length);
        this.backtrace = backtrace;
        this.exitStoppingJVM = exitStoppingJVM;
        this.in = in;
        this.out = out;
        this.err = err;
        this.awt = awt;
        this.bareCanvas = bareCanvas;
        this.javaxSound = javaxSound;
        this.jdbm = jdbm;
        this.os = os;
        this.unixEmulation = unixEmulation;
        this.file = file;
        this.embedded = embedded;
        this.embeddedBase = embeddedBase;
    } // end constructor(String[], boolean, boolean, InputStream, ...)

    /**
     * "Parses" a boolean switch value.
     * @param value value to parse (can be <tt>null</tt>)
     * @return <tt>true</tt> if passed value is <tt>"on"</tt>,
     *         <tt>false</tt> if passed value is <tt>"off"</tt>
     * @throws CadmiumException if passed value is neither <tt>"on"</tt>
     *                              nor <tt>"off"</tt>
     */
    static Boolean valueOfBoolean(final String value)
        throws CadmiumException {
        if ("on".equals(value)) {
            return Boolean.TRUE;
        } else if ("off".equals(value)) {
            return Boolean.FALSE;
        } else {
            throw new CadmiumException("switch value should be either 'on' or 'off'");
        } // end if/elsif
    } // end method 'valueOfBoolean(String)'

    /**
     * "Parses" an integer switch value.
     * @param value value to parse (can be <tt>null</tt>)
     * @return corresponding integer value
     * @throws CadmiumException if passed value is not an integer
     */
    static Integer valueOfInteger(final String value)
        throws CadmiumException {
        try {
            return Integer.valueOf(value);
        } catch (final NumberFormatException nfe) {
            throw new CadmiumException("switch value should be an integer");
        } // end try/catch
    } // end method 'valueOfInteger(String)'

    /**
     * "Parses" an OS switch value.
     * @param value value to parse (can be <tt>null</tt>)
     * @return corresponding OS value
     * @throws CadmiumException if passed value is not an OS
     */
    static String valueOfOS(final String value)
        throws CadmiumException {
        if (("Unix".equals(value))
            || ("Cygwin".equals(value))
            || ("Win32".equals(value))
            || ("MacOS".equals(value))
            || ("Cadmium".equals(value))) {
            return value;
        } else {
            throw new CadmiumException("invalid os identifier");
        } // end if/else
    } // end method 'valueOfOS(String)'

    /**
     * "Parses" a providers switch value.
     * @param value value to parse (can be <tt>null</tt>)
     * @return corresponding providers value
     */
    static String[] valueOfProviders(final String value) {
        return value == null ? new String[0] : value.split(",");
    } // end method 'valueOfProviders(String)'

    /**
     * Converts an array of providers into a single string.
     * @param prov providers - should not be <tt>null</tt>
     * @return providers as a single comma-separated string
     */
    static String providersToString(final String[] prov) {
        assert prov != null : "null prov";
        final int len = prov.length;
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < len; i++) {
            if (i > 0) {
                sb.append(',');
            } // end if
            sb.append(prov[i]);
        } // end for
        return sb.toString();
    } // end method 'providersToString(String[])'

    /**
     * Returns the arguments to program.
     * @return the arguments to program
     */
    public final String[] getArguments() {
        return Arrays.copyOf(this.arguments, this.arguments.length);
    } // end method 'getArguments()'

    /**
     * Tests whether backtrace print is requested.
     * @return <tt>true</tt> if backtrace is requested,
     *         <tt>false</tt> otherwise
     */
    public final boolean isBacktraceRequested() {
        return this.backtrace;
    } // end method 'isBacktraceRequested()'

    /**
     * Tests whether <i>exit</i> primitive should stop JVM.
     * @return <tt>true</tt> if <i>exit</i> primitive should stop JVM,
     *         <tt>false</tt> otherwise
     */
    public final boolean isExitStoppingJVM() {
        return this.exitStoppingJVM;
    } // end method 'isExitStoppingJVM()'

    /**
     * Returns the standard input of program.
     * @return the standard input of program
     */
    public final InputStream getStandardInput() {
        return this.in;
    } // end method 'getStandardInput()'

    /**
     * Returns the standard output of program.
     * @return the standard output of program
     */
    public final PrintStream getStandardOutput() {
        return this.out;
    } // end method 'getStandardOutput()'

    /**
     * Returns the standard error of program.
     * @return the standard error of program
     */
    public final PrintStream getStandardError() {
        return this.err;
    } // end method 'getStandardError()'

    /**
     * Tests whether <i>Graphics</i> frame should be AWT.
     * @return <tt>true</tt> if <i>Graphics</i> frame should be AWT,
     *         <tt>false</tt> otherwise
     */
    public final boolean isFrameAWT() {
        return this.awt;
    } // end method 'isFrameAWT()'

    /**
     * Tests whether <i>Graphics</i> component should be a bare canvas
     * (no frame).
     * @return <tt>true</tt> if <i>Graphics</i> component should be a bare canvas,
     *         <tt>false</tt> otherwise
     */
    public final boolean isBareCanvas() {
        return this.bareCanvas;
    } // end method 'isBareCanvas()'

    /**
     * Tests whether <tt>javax.sound</tt> should be used for <i>Graphics</i>
     * beeps.
     * @return <tt>true</tt> if <tt>javax.sound</tt> should be used for <i>Graphics</i> beeps,
     *         <tt>false</tt> otherwise
     */
    public final boolean isJavaxSoundUsed() {
        return this.javaxSound;
    } // end method 'isJavaxSoundUsed()'

    /**
     * Tests whether <i>JDBM</i> should be used for <i>Dbm</i> implementation.
     * @return <tt>true</tt> if <i>JDBM</i> should be used for <i>Dbm</i> implementation,
     *         <tt>false</tt> otherwise
     */
    public final boolean isJDBMUsed() {
        return this.jdbm;
    } // end method 'isJDBMUsed()'

    /**
     * Returns OS identifier.
     * @return OS identifier
     */
    public final String getOS() {
        return this.os;
    } // end method 'getOS()'

    /**
     * Tests whether unix primitives should be emulated.
     * @return <tt>true</tt> if unix primitives should be emulated,
     *         <tt>false</tt> otherwise
     */
    public final boolean isUnixEmulated() {
        return this.unixEmulation;
    } // end method 'isUnixEmulated()'

    /**
     * Returns the program file.
     * @return the program file
     */
    public final String getFile() {
        return this.file;
    } // end method 'getFile()'

    /**
     * Tests whether <i>embedded mode</i> is activated.
     * @return <tt>true</tt> if <i>embedded mode</i> is activated,
     *         <tt>false</tt> otherwise
     */
    public final boolean isEmbedded() {
        return this.embedded;
    } // end method 'isEmbedded()'

    /**
     * Returns the base class used by embedded mode.
     * @return the base class used by embedded mode
     */
    public final String getEmbeddedBase() {
        return this.embeddedBase;
    } // end method 'getEmbeddedBase()'

} // end class 'AbstractParameters'
